﻿using System;
using Bookvar.Common;
using Bookvar.ObjectModel;
using Bookvar.ObjectModel.Collections;
using Bookvar.ServiceModel;
using Bookvar.UI;
using LocalizationResources = Bookvar.UI.Localization.Resources;

namespace BookvarWpf
{
    /// <summary>
    /// This mind map service uses the <see cref="MindMapPanel"/> to provide info about the current <see cref="MindMap"/>.
    /// </summary>
    /// TODO: Move some of the <see cref="MainPage"/> logic to this class.
    internal class MindMapService : IMindmapService
    {
        private readonly MainPage mainPage;
        private readonly MindMapPanel mindMapPanel;

        /// <summary>
        /// Initializes a new instance of the <see cref="MindMapService"/> class.
        /// </summary>
        /// <param name="mindMapPanel">The mind map panel.</param>
        /// <param name="mainPage">The main page</param>
        public MindMapService( MindMapPanel mindMapPanel, MainPage mainPage )
        {
            if ( mindMapPanel == null )
            {
                throw new ArgumentNullException( "mindMapPanel" );
            }
            if ( mainPage == null ) throw new ArgumentNullException( "mainPage" );

            this.mindMapPanel = mindMapPanel;
            this.mainPage = mainPage;
        }

        #region IMindMapService Members

        /// <summary>
        /// Gets the current active mind map.
        /// </summary>
        /// <value>The current active mind map.</value>
        public MindMap CurrentMindmap
        {
            get { return mindMapPanel.Mindmap; }
        }

        /// <summary>
        /// Gets all the loaded mind maps.
        /// </summary>
        /// <value>The loaded mind maps.</value>
        public MindmapCollection LoadedMindMaps
        {
            get { return mainPage.LoadedMaps; }
        }

        /// <summary>
        /// Gets the currently selected topic. Returns <a>null</a> if no topic is selected.
        /// </summary>
        /// <value>The currently selected topic.</value>
        /// <exception cref="ArgumentNullException">if <a>value</a> is null.</exception>
        /// <exception cref="ArgumentException">if the provided topic is not in the current <see cref="MindMap"/></exception>
        public Topic SelectedTopic
        {
            get { return mindMapPanel.SelectedTopic; }
            set
            {
                if ( value == null )
                {
                    throw new ArgumentNullException( "value" );
                }
                if ( mindMapPanel.Mindmap.ContainsTopic( value ) == false )
                {
                    throw new ArgumentException( LocalizationResources.ExceptionProvidedTopicNotInTheCurrentMindMap );
                }

                mindMapPanel.SelectedTopic = value;
            }
        }

        /// <summary>
        /// Adds the <see cref="MindMap"/> to the opened mind maps.
        /// The <see cref="MindMap"/> is automatically focused.
        /// </summary>
        /// <param name="mindmap">The mind map.</param>
        public void AddMindmap( MindMap mindmap )
        {
            AddMindmap( mindmap, true );
        }

        /// <summary>
        /// Adds the <see cref="MindMap"/> to the opened mind maps.
        /// The <see cref="MindMap"/> will be focused if the focus parameter is <a>true</a>.
        /// </summary>
        /// <param name="mindmap">The mind map.</param>
        /// <param name="switchToMindmap">Indicates if the <see cref="MindMap"/> should be automatically
        /// focused after it is added.</param>
        public void AddMindmap( MindMap mindmap, bool switchToMindmap )
        {
            if ( mindmap == null )
            {
                throw new ArgumentNullException( "mindmap" );
            }

            mainPage.LoadedMaps.Add( mindmap );
            if ( switchToMindmap )
            {
                SwitchToMindmap( mindmap );
            }
        }

        /// <summary>
        /// Switches to the the specified <see cref="MindMap"/>.
        /// </summary>
        /// <param name="mindmap">The mind map that will be focused after the switch.</param>
        /// <exception cref="ArgumentNullException">if the <paramref name="mindmap"/> is null.</exception>
        public void SwitchToMindmap( MindMap mindmap )
        {
            mainPage.FocusMindmap( mindmap );
        }

        /// <summary>
        /// Opens a mind map from the specified path on the disk. After the map is loaded the focus automatically is
        /// switched to it. 
        /// <BR/>
        /// If the mind map is already open it will not be loaded again. But it will be focused.
        /// </summary>
        /// <exception cref="ArgumentException">
        /// if <paramref name="filePath"/> is null or null.
        /// </exception>
        /// <param name="filePath">The file path.</param>
        /// <returns>The opened MindMap. It does not matter if the map was already opened - it is still returned.</returns>
        public MindMap OpenMindmapFromDisk( string filePath )
        {
            return OpenMindmapFromDisk( filePath, true );
        }

        /// <summary>
        /// Opens a mind map from the specified path on the disk. If the <paramref name="switchToMapAutomatically"/>
        /// is true, the focus will be switched to the newly opened <see cref="MindMap"/>.
        /// <BR/>
        /// If the mind map is already open it will not be loaded again.
        /// </summary>
        /// <exception cref="ArgumentException">
        /// if <paramref name="filePath"/> is null or null.
        /// </exception>
        /// <param name="filePath">The file path.</param>
        /// <param name="switchToMapAutomatically">Indicates if the map should be focused after it is loaded.</param>
        /// <returns>The opened MindMap. It does not matter if the map was already opened - it is still returned.</returns>
        public MindMap OpenMindmapFromDisk( string filePath, bool switchToMapAutomatically )
        {
            if ( string.IsNullOrEmpty( filePath ) )
            {
                throw new ArgumentException( "Parameter 'filePath' is null or empty." );
            }

            MindMap openedMap;
            MindMap alreadyLoadedMap = MainPage.PersistenceService.GetLoadedMapByFilePath( filePath );

            if ( alreadyLoadedMap != null )
            {
                if ( switchToMapAutomatically )
                {
                    SwitchToMindmap( alreadyLoadedMap );
                }

                openedMap = alreadyLoadedMap;
            }
            else
            {
                //TODO: fix calling MainPage and RecentFiles static methods.
                var newMap = new MindMap();
                MainPage.PersistenceService.RegisterMindmapForPersistence( newMap, filePath );
                RecentFiles.AddFileToRecent( filePath );
                newMap = MainPage.PersistenceService.LoadMapFromPersistence( newMap.Key );
                AddMindmap( newMap, switchToMapAutomatically );
                openedMap = newMap;
            }

            return openedMap;
        }

        #endregion
    }
}